/**
 *  This is free software licensed and distributed under 
 *  the terms and conditions of the 
 * GNU Lesser General Public License (LGPL) Version 3.0 .
 * 
 * http://www.gnu.org/licenses/lgpl.html
 *
 * @author Markus Kosmal
 */
package org.mko.html5.client.basecomponents.rangeslider;

import java.util.HashMap;

import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Random;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;

// TODO: Auto-generated Javadoc
/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class RangeSliderFactory {

    /** The name. */
    private String name;

    /** The range slider collection. */
    private final HashMap<String, Element> rangeSliderCollection = new HashMap<String, Element>();

    /** The value. */
    private double value;

    /** The step. */
    private double step;

    /** The min. */
    private double min;

    /** The max. */
    private double max;

    /** The current id. */
    private String currentId;

    /** The event bus. */
    private EventBus eventBus;

    /** The default name. */
    private final String defaultName = "default";

    /** The random string length. */
    private final int randomStringLength = 8;

    /** The random string all letters count. */
    private final int randomStringAllLettersCount = 26;

    /**
     * Instantiates a new range slider factory.
     */
    public RangeSliderFactory() {

    }

    /**
     * Creates a new RangeSlider object.
     * 
     * @param step
     *            the step
     * @param min
     *            the min
     * @param max
     *            the max
     * @param value
     *            the value
     * @param eventBus
     *            the event bus
     * @return the flow panel
     */
    public final FlowPanel createRangeSliderBox(final double step, final double min, final double max, final double value, final EventBus eventBus) {
        FlowPanel flowPanel = new FlowPanel();

        final Element element = this.createRangeSlider(step, min, max, value, eventBus);
        RangeSlider rangeSlider = new RangeSlider();
        rangeSlider.setContent(element);

        HTML range = new HTML("<form>" + element.getString() + "</form>");

        flowPanel.add(range);

        Button btnSubmit = new Button("Übernehmen");

        btnSubmit.addClickHandler(new ClickHandler() {

            @Override
            public void onClick(final ClickEvent event) {
                RangeSliderValueChangedEvent rangeSliderValueChangedEvent = new RangeSliderValueChangedEvent(Double.parseDouble(element.getAttribute("value")));
                RangeSliderFactory.this.eventBus.fireEventFromSource(rangeSliderValueChangedEvent, element);
            }
        });

        flowPanel.add(btnSubmit);

        return flowPanel;
    }

    /**
     * Creates a new RangeSlider object.
     * 
     * @param step
     *            the step
     * @param min
     *            the min
     * @param max
     *            the max
     * @param value
     *            the value
     * @param eventBus
     *            the event bus
     * @return the element
     */
    private Element createRangeSlider(final double step, final double min, final double max, final double value, final EventBus eventBus) {
        this.step = step;
        this.min = min;
        this.max = max;
        this.name = this.defaultName;
        this.value = value;
        this.eventBus = eventBus;

        return this.createRangeInputElement();
    }

    /**
     * Creates a new RangeSlider object.
     * 
     * @return the element
     */
    private Element createRangeInputElement() {
        Element e = DOM.createElement("input");
        e.setAttribute("type", "range");
        if (this.name != null) {
            e.setAttribute("name", this.name);
        }

        e.setAttribute("value", String.valueOf(this.value));
        e.setAttribute("step", String.valueOf(this.step));
        e.setAttribute("min", String.valueOf(this.min));
        e.setAttribute("max", String.valueOf(this.max));

        boolean run = true;

        String id = "";
        while (run) {
            id = this.getRandomString();
            if (!this.rangeSliderCollection.containsKey(id)) {
                run = false;
            }
        }
        this.currentId = id;
        e.setId(id);
        this.rangeSliderCollection.put(id, e);

        return e;
    }

    /**
     * Gets the random string.
     * 
     * @return the random string
     */
    private String getRandomString() {
        String string = "abcdefghijklmnopqrstuvwxyz";
        String id = "";
        for (int i = 0; i < this.randomStringLength; i++) {
            id += string.charAt(Random.nextInt(this.randomStringAllLettersCount));
        }
        return id;
    }

    /**
     * Gets the name.
     * 
     * @return the name
     */
    public final String getName() {
        return this.name;
    }

    /**
     * Sets the name.
     * 
     * @param name
     *            the name to set
     */
    public final void setName(final String name) {
        this.name = name;
    }

    /**
     * Gets the value.
     * 
     * @return the value
     */
    public final double getValue() {
        return this.value;
    }

    /**
     * Sets the value.
     * 
     * @param value
     *            the value to set
     */
    public final void setValue(final double value) {
        this.value = value;
    }

    /**
     * Gets the step.
     * 
     * @return the step
     */
    public final double getStep() {
        return this.step;
    }

    /**
     * Sets the step.
     * 
     * @param step
     *            the step to set
     */
    public final void setStep(final double step) {
        this.step = step;
    }

    /**
     * Gets the min.
     * 
     * @return the min
     */
    public final double getMin() {
        return this.min;
    }

    /**
     * Sets the min.
     * 
     * @param min
     *            the min to set
     */
    public final void setMin(final double min) {
        this.min = min;
    }

    /**
     * Gets the max.
     * 
     * @return the max
     */
    public final double getMax() {
        return this.max;
    }

    /**
     * Sets the max.
     * 
     * @param max
     *            the max to set
     */
    public final void setMax(final double max) {
        this.max = max;
    }

}
